<?php
/**
 * Created by PhpStorm.
 * User: Appla
 * Date: 2017/5/16
 * Time: 10:43
 */

namespace test;

use DateTime;
use artisan\cache;
use Redis;

/**
 * 统计Curl请求的情况记录HTTP状态和Curl请求状态
 * HTTP status codes:
 * @see https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
 * @see https://curl.haxx.se/libcurl/c/libcurl-errors.html
 * curl error code最大没有超过100,所以直接和HTTP状态码混用了
 * Class CurlRequestLogger
 * @package test
 */
class CurlRequestLogger
{
    const CACHE_KEY_TPL = 'CurlRequestLogs:HTTPStatusCode:%s:%s';

    const CACHE_KEY_PREFIX = 'CurlRequestLogs:HTTPStatusCode:';

    const CACHE_INSTANCE_ID = 'ivr';

    const REDIS_CONFIG = [
        // '127.0.0.1',
        // '6379',
        '192.168.1.77',
        6380,
    ];

    const TIME_FORMAT = 'YmdHi';

    const MAX_TTL = 3600;

    /**
     * @var self
     */
    private static $instance;

    /**
     * @var \artisan\cache\PHPredisDriver|\Redis
     */
    private static $cacheInstance;

    /**
     * @var array
     */
    private $curlInfo;

    /**
     * @var int
     */
    private $instantiatedTime;

    /**
     * @var bool
     */
    private static $logEnabled = true;

    /**
     * CurlRequestLogger constructor.
     */
    protected function __construct()
    {
        $this->instantiatedTime = time();
        //self::$logEnable = ;
    }

    /**
     * @param resource $ch
     * @return array|mixed
     */
    public static function getCurlInfo($ch)
    {
        $info = [];
        if(is_resource($ch) && $info = curl_getinfo($ch)){
            $info['error_info'] = curl_error($ch);
            $info['error_code'] = curl_errno($ch);
        }
        return $info;
    }

    /**
     * @param array|resource $info
     * @param string|null $url
     * @return bool|int
     */
    public static function log($info, $url = null)
    {
        if(!self::$logEnabled){
            return 0;
        }
        if(is_resource($info)){
            $info = self::getCurlInfo($info);
        }
        $url && $info['url'] = $url;
        return self::getInstance()->init($info)->write();
    }

    /**
     * @return bool|int
     */
    private function write()
    {
        return $this->curlInfo ? self::getCacheInstance()->hIncrBy($cacheKey = $this->buildCacheKey(), $this->curlInfo['http_code'] ?: $this->curlInfo['error_code'], 1) && self::getCacheInstance()->expire($cacheKey, self::MAX_TTL) : 0;
    }

    /**
     * @return \artisan\cache\PHPredisDriver|\Redis
     */
    private static function getCacheInstance()
    {
        return self::$cacheInstance ?: self::$cacheInstance = (function () {
            $redis = new Redis();
            $redis->connect(...self::REDIS_CONFIG);
            return $redis;
        })();
//        return self::$cacheInstance ?: self::$cacheInstance = cache::connect(self::CACHE_INSTANCE_ID);
    }

    /**
     * @return string
     */
    private function buildCacheKey()
    {
        return sprintf(self::CACHE_KEY_TPL, $this->getTimeStr(), $this->getUrl());
    }

    /**
     * @return string
     */
    private function getUrl()
    {
        return self::parseUrl($this->curlInfo['url']);
    }

    /**
     * @param $url
     * @return string
     */
    public static function parseUrl($url)
    {
        //$urlArr = parse_url($url);
        return preg_replace('~^https?://|\?.*$~i', '', $url);
    }

    /**
     * @return string
     */
    private function getTimeStr()
    {
        return (new DateTime())->format(self::TIME_FORMAT);
    }

    /**
     * @param array $curlInfo
     * @return $this
     */
    private function init(array $curlInfo)
    {
        $this->curlInfo = $curlInfo;
        return $this;
    }

    /**
     * @return CurlRequestLogger
     */
    private static function getInstance()
    {
        return self::$instance ?: self::$instance = new self();
    }

    /**
     * @return string
     */
    private function getUrlHash()
    {
        return md5($this->getUrl());
    }
}
